"""
-----脚本能力-----
仅可执行脚本化的历战NPC战斗
使用前请确保你的战斗序列每次都可以以完全相同的流程进行
如果需要死人也请死同一位角色，脚本无法应对随机状况

-----脚本状态-----
脚本架构：完成
已适配历战NPC：已适配全部8人，适用于台服及国际服

-----已知问题-----未解决-----
1. 大地图有概率双击，虽不影响本脚本运行，但会影响其他情况的使用。 - 增加延迟观察效果 - 待验证 - 目前稳定
-----已知问题-----已解决-----
1. 技能点击失效，推测原因为卡顿状态下，按键快于面板就绪。 - 加入重试机制 - 无复现
2. 技能面板开启失效，推测原因为过快点击致使面板关闭。 - 加入重试机制 - 无复现
3. Boost等级使用错误，加延迟无法避免。 - 加入检查及重试机制 - 无复现
-----已知问题-----状态未知-----
1. 切换角色不成功，极低概率出现 - 未应对 - 无法复现

-----后续改进计划-----
0. （优先）更新UI，战斗序列生成工具，适配分享功能
1. 角色技能使用可能需要指定目标，目前尚未适配，今后增加。
2. 角色必杀，今后增加。
3. 其他重要脚本：亚久斯特脚本，斗技大会脚本，黑龙脚本。

-----使用方法-----
修改四个使用者参数
1. 修改targeting_npc，指定目标为哪位历战NPC
2. 修改battle_sequence, 指定你设计的战斗序列
3. 修改region，指定台服或国际服，默认台服
4. 修改round_per_recover, 目前建议不修改，有能力2T以后再调高此参数
5. 在城市旅店门口启动脚本
"""

from time import *
from PyGameAutoAndroid import *

#   -------------------------------------------------------------------------------------------------
#   使用者参数部分 - 通过调整参数改变脚本功能
#   -------------------------------------------------------------------------------------------------
#   targeting_npc - 配置脚本目标为哪位历战NPC
#       可选值: 'bt_axe'    - 历战斧 - 瓦洛雷
#              'bt_bow'    - 历战弓 - 恩波格洛
#              'bt_tome'   - 历战书 - 希亚特珀利斯
#              'bt_spear'  - 历战枪 - 利布尔泰德
#              'bt_dagger' - 历战匕 - 克拉古斯比亚
#              'bt_staff'  - 历战杖 - 库利亚布鲁克
#              'bt_fan'    - 历战扇 - 桑谢德
#              'bt_blade'  - 历战剑 - 利布尔泰德

targeting_npc = "bt_staff"

#   battle_sequence - 预设战斗序列 - 此设计为临时方案
#                     由于每位玩家拥有的角色，技能，星级均不同，技能位置，队伍组成也不同，因此这段必须自己设计并提供数值
#                     此参数为object array：
#                           第1层为战斗回合层，数组有多少对象元素就有多少战斗回合
#                           第2层为战斗对象层，对象有两个字段
#                               all_boost  - 是否需要按下全体boost按钮
#                               skill_list - 只有4个元素，分别代表从上到下第1234位角色
#
#                           skill_list内为角色技能层，只有2个元素，第一个元素为使用哪个技能，第二个元素为使用几级Boost
#                           关于技能，可选值为-1, 0, 1, 2, 3, 10, 11, 12, 13
#                               -1 - 跳过本角色
#                               0  - 使用普攻
#                               1  - 使用第一个技能
#                               2  - 使用第二个技能
#                               3  - 使用第三个技能
#                               10 - 交换角色，使用普攻
#                               11 - 交换角色，使用第一个技能
#                               12 - 交换角色，使用第二个技能
#                               13 - 交换角色，使用第三个技能
#                           关于Boost，可选值为1, 2, 3, 4
#                               1  - 无Boost
#                               2  - 2级Boost
#                               3  - 3级Boost
#                               4  - 满级Boost

battle_sequence = [
    # 第1回合
    {
        'skill_list': [
            [1, 1, 1, 0],
            [1, 1, 0, 0],
            [1, 4, 0, 0],
            [3, 1, 0, 0],
        ],
        'all_boost': False,
    },
    # 第2回合
    {
        'skill_list': [
            [13, 4, 0, 0],
            [11, 4, 0, 'tikilen'],
            [13, 1, 0, 0],
            [3, 1, 0, 'elite-mercenary'],
        ],
        'all_boost': False,
    },
    # 第3回合
    {
        'skill_list': [
            [11, 1, 1, 0],
            [11, 1, 0, 0],
            [-1, 1, 0, 0],
            [12, 4, 0, 0],
        ],
        'all_boost': False,
    },
    # 第4回合
    {
        'skill_list': [
            [2, 1, 0, 0],
            [-1, 1, 0, 0],
            [-1, 1, 0, 0],
            [12, 1, 0, 0],
        ],
        'all_boost': True,
    },
    # 第5回合
    {
        'skill_list': [
            [1, 1, 1, 0],
            [11, 1, 0, 0],
            [11, 4, 0, 0],
            [3, 1, 0, 0],
        ],
        'all_boost': False,
    },
    # 第6回合
    {
        'skill_list': [
            [2, 1, 0, 0],
            [2, 4, 0, 0],
            [13, 1, 0, 0],
            [3, 1, 0, 'veteran-mercenary'],
        ],
        'all_boost': False,
    },
    # 第7回合
    {
        'skill_list': [
            [13, 4, 0, 0],
            [11, 4, 0, 0],
            [-1, 1, 0, 0],
            [12, 4, 0, 0],
        ],
        'all_boost': False,
    },
    # 第8回合
    {
        'skill_list': [
            [12, 1, 0, 0],
            [5, 1, 0, 0],
            [-1, 1, 0, 0],
            [11, 1, 0, 0],
        ],
        'all_boost': True,
    },
    # 第9回合
    {
        'skill_list': [
            [12, 4, 0, 0],
            [1, 1, 0, 0],
            [2, 1, 0, 0],
            [11, 1, 0, 0],
        ],
        'all_boost': False,
    },
    # 第10回合
    {
        'skill_list': [
            [-1, 1, 0, 0],
            [-1, 1, 0, 0],
            [-1, 1, 0, 0],
            [1, 4, 0, 0],
        ],
        'all_boost': False,
    },
    # 第11回合
    {
        'skill_list': [
            [-1, 1, 0, 0],
            [2, 1, 0, 0],
            [-1, 1, 0, 0],
            [13, 1, 0, 0],
        ],
        'all_boost': True,
    },
    # 第n回合 - 如有需求可以一直加下去，但要保证你的战斗流程每次都相同，不可以这次战斗4回合，下次战斗5回合
]

#   region - 区服代码
#       可选值: 'tw'    - 台服
#              'en'    - 美服
region = 'en'

#   round_per_recover - 每次回旅店回血后连续与历战NPC战斗的场次 - 默认1次
round_per_recover = 1

#   -------------------------------------------------------------------------------------------------
#                               ※如果不懂编程或看不懂代码，从这里往下可以不用看了※
#   -------------------------------------------------------------------------------------------------
#   开发者参数部分 - 通过调整参数改变脚本性能
stability_mode = 0
turn_on_in_game_log = False
turn_on_console_log = True

valore_main_boulevard_coord = [296, 478]
emberglow_east_district_coord = [932, 452]
emberglow_laboratory_coord = [759, 347]
emberglow_laboratory_to_town_coord = [272, 544]
cragspear_slums_coord = [841, 616]
theatropolis_library_coord = [447, 416]
rippletide_residence_coord = [797, 337]

#   常数部分 - 游戏内固定参数，比如地图按钮的位置。
#   当更换设备时，由于屏幕分辨率发生变化，这些数值都会失效，放在这里统一更改，比去代码里寻找效率更高。
#   单点坐标常数
screen_center_coord = [640, 360]  # 屏幕正中
minimap_coord = [1078, 137]  # 主界面 - 小地图上箭头坐标
party_btn_coord = [215, 605]  # 主界面 - 大陆地图按钮坐标
worldmap_btn_coord = {  # 主界面 - 队伍按钮坐标
    'tw': [468, 605],
    'en': [730, 605],
}
allies_list_btn_coord = [116, 543]  # 队伍界面 - 支援者列表按钮坐标
first_ally_coord = [387, 256]  # 支援者列表 - 第一位支援者位置坐标
part_ways_btn_coord = [796, 597]  # 支援者列表 - 告别按钮位置
general_ok_btn_coord = [800, 480]  # 菜单界面 - 通用OK按钮坐标，如：确认告别的OK按钮，确认大地图前往某处的是按钮
close_menu_btn_coord = [1236, 22]  # 菜单界面 - 右上角叉按钮位置
inquire_btn_coord = [1176, 626]  # 主界面 - 打听按钮位置
impress_btn_coord = [1043, 400]  # 打听界面 - 收服按钮位置
confirm_impress_btn_coord = [763, 500]  # 收服界面 - 收服按钮位置
lower_ok_btn_coord = [800, 514]  # 菜单界面 - 低位OK按钮坐标，如：确认收服OK按钮，确认住店按钮
center_ok_btn_coord = [642, 480]  # 菜单界面 - 中间OK按钮坐标
worldmap_proceed_btn_coord = [1051, 641]  # 世界地图 - 前往这里按钮位置
skills_panel_coord = [[1150, 90],
                      [1150, 230],
                      [1150, 370],
                      [1150, 520]]
switch_character_coord = {
    'tw': [793, 626],
    'en': [1105, 635],
}
skills_coord = {
    'tw': [[[850, 170, 0, 0],
            [850, 170, 1025, 170],
            [850, 170, 1115, 170],
            [850, 170, 1200, 170]],
           [[850, 290, 0, 0],
            [850, 290, 1025, 290],
            [850, 290, 1115, 290],
            [850, 290, 1200, 290]],
           [[850, 400, 0, 0],
            [850, 400, 1025, 400],
            [850, 400, 1115, 400],
            [850, 400, 1200, 400]],
           [[850, 520, 0, 0],
            [850, 520, 1025, 520],
            [850, 520, 1115, 520],
            [850, 520, 1200, 520]]],
    'en': [[[850, 200, 0, 0],
            [850, 200, 1025, 170],
            [850, 200, 1115, 170],
            [850, 200, 1200, 170]],
           [[850, 305, 0, 0],
            [850, 305, 1025, 290],
            [850, 305, 1115, 290],
            [850, 305, 1200, 290]],
           [[850, 410, 0, 0],
            [850, 410, 1025, 400],
            [850, 410, 1115, 400],
            [850, 410, 1200, 400]],
           [[850, 525, 0, 0],
            [850, 525, 1025, 520],
            [850, 525, 1115, 520],
            [850, 525, 1200, 520]]],
}
start_battle_btn_coord = [1083, 643]
all_boost_btn_coord = [864, 643]
flee_battle_btn_coord = [535, 645]

inn_exit_coord = {
    'valore': [534, 447],
    'emberglow': [534, 447],
    'theatropolis': [645, 447],
    'rippletide': [533, 447],
    'cragspear': [526, 448],
    'clearbrook': [498, 448],
    'sunshade': [695, 404],
    'shepherds-rock': [552, 447],
}

get_town_name_by_npc = {
    'bt_axe': 'valore',
    'bt_bow': 'emberglow',
    'bt_tome': 'theatropolis',
    'bt_spear': 'rippletide',
    'bt_dagger': 'cragspear',
    'bt_staff': 'clearbrook',
    'bt_fan': 'sunshade',
    'bt_blade': 'shepherds-rock',
}

bt_npc_coord_on_minimap = {
    'bt_axe': [845, 469],
    'bt_bow': [679, 541],
    'bt_tome': [0, 0],
    'bt_spear': [0, 0],
    'bt_dagger': [727, 535],
    'bt_staff': [741, 302],
    'bt_fan': [284, 270],
    'bt_blade': [760, 391],
}

#   多点找色常数
minimap_exist = ["#E2D57E", "1|0|#E2D57E", [1078, 137, 1080, 138]]
menu_exist = {
    'tw': ["#F0EBE8", "0|1|#F0EBE8", [523, 639, 524, 641]],  # 使用了世界地图的文字做判断，以后更新会导致失效，需要更新脚本
    'en': ["#F0EBE8", "0|1|#F0EBE8", [943, 622, 944, 624]],  # 使用了Hint的文字做判断，以后更新会导致失效，需要更新脚本
}
menu_opened = {
    'tw': ["#E9E9E9", "1|1|#E9E9E9", [1235, 19, 1237, 21]],
    'en': ["#E9E9E9", "1|1|#E9E9E9", [1236, 20, 1238, 22]],
}
character_standby = ["#F0EBE8", "1|0|#F0EBE8", [681, 168, 683, 169]]
battle_idling = {
    'tw': ["#FFFFFF", "1|1|#FFFFFF", [1082, 642, 1084, 644]],
    'en': ["#FFFFFF", "1|1|#FFFFFF", [1038, 629, 1040, 631]],
}
black_screen_exist = ["#000000", "1|1|#000000", [639, 359, 641, 361]]
town_menu_opened = {
    'tw': ["#FFFFFF", "0|1|#FFFFFF", [1020, 647, 1021, 649]],
    'en': ["#FFFFFF", "0|1|#FFFFFF", [1001, 636, 1002, 638]],
}
ok_move_exist = {
    'tw': ["#FFFFFF", "0|1|#FFFFFF", [798, 485, 799, 487]],
    'en': ["#FFFFFF", "0|1|#FFFFFF", [783, 479, 784, 481]],
}
inquire_exist = ["#62AAAA", "0|1|#5C6F6F", [1076, 656, 1100, 658]]
inquire_menu_opened = ["#58BBB0", "1|1|#58BBB0", [1150, 279, 1159, 282]]
confirm_impress_exist = {
    'tw': ["#FFFFFF", "0|1|#FFFFFF", [764, 494, 765, 496]],
    'en': ["#FFFFFF", "1|0|#FFFFFF", [764, 495, 766, 496]],
}
character_all_boosted = ["#DEDEDE", "1|0|#F0F0F0", [905, 638, 907, 639]]

skills_panel_exist = [["#FFFFFF", "0|1|#FFFFFF", [999, 125, 1000, 127]],
                      ["#FFFFFF", "0|1|#FFFFFF", [999, 268, 1000, 270]],
                      ["#FFFFFF", "0|1|#FFFFFF", [999, 411, 1000, 413]],
                      ["#FFFFFF", "0|1|#FFFFFF", [999, 554, 1000, 556]]]
skills_panel_standby = {
    'tw': ["#F0EBE8", "-48|9|#6F6F6F", [633, 168, 682, 178]],
    'en': ["#6F6F6F", "52|-8|#F0EBE8", [633, 191, 686, 200]],
}
# switch_character_btn_exist = ["#272727", "19|0|#363635, 8|-9|#262626, 0|11|#262626, 19|11|#262626", [680, 615, 700, 636]]
# cancel_switch_character_btn_exist = ["#272727", "19|0|#373635, 8|-9|#262626, 0|11|#262626, 19|11|#262626", [728, 615, 748, 636]]
switch_character_done = {
    'tw': ["#272727", "19|0|#373635, 8|-9|#262626, 0|11|#262626, 19|11|#262626", [728, 615, 748, 636]],     # 取消交替按钮存在，代表交替完成
    'en': ["#F0EBE8", "1|1|#F0EBE8", [783, 20, 785, 22]],       # 检查技能面板上方Front和Back
}

allies_list_btn_exist = {
    'tw': ["#FFFFFF", "0|1|#FFFFFF", [116, 543, 117, 545]],
    'en': ["#FFFFFF", "0|1|#FFFFFF", [51, 534, 52, 536]],
}
allies_list_opened = {
    'tw': ["#F0EBE8", "1|1|#F0EBE8", [267, 104, 269, 106]],
    'en': ["#F0EBE8", "1|1|#F0EBE8", [260, 102, 262, 104]],
}
# ally_chose = ["#FFFFFF", "1|0|#FFFFFF", [784, 596, 786, 597]]
ally_parting_ways = {
    'tw': ["#FFFFFF", "0|1|#FFFFFF", [785, 481, 786, 483]],
    'en': ["#FFFFFF", "0|1|#FFFFFF", [785, 482, 786, 484]],
}

inn_exist = {
    'valore': ["#FFFFFF", "0|1|#FFFFFF", [628, 203, 629, 205]],
    'emberglow': ["#FFFFFF", "0|1|#FFFFFF", [628, 167, 629, 169]],
    'theatropolis': ["#FFFFFF", "0|1|#FFFFFF", [628, 246, 629, 248]],
    'rippletide': ["#FFFFFF", "0|1|#FFFFFF", [628, 237, 629, 239]],
    'cragspear': ["#FFFFFF", "0|1|#FFFFFF", [628, 233, 629, 235]],
    'clearbrook': ["#FFFFFF", "0|1|#FFFFFF", [628, 242, 629, 244]],
    'sunshade': ["#FFFFFF", "0|1|#FFFFFF", [628, 238, 629, 240]],
    'shepherds-rock': ["#FFFFFF", "0|1|#FFFFFF", [628, 230, 629, 232]],
}
inn_host_exist = {
    'valore': ["#A19E94", "13|-13|#9F9891, 4|5|#54544E", [696, 278, 710, 297]],
    'emberglow': ["#A19E94", "13|-13|#9F9891, 4|5|#54544E", [670, 272, 684, 291]],
    'theatropolis': ["#A19E94", "13|-13|#9F9891, 4|5|#54544E", [549, 268, 593, 301]],
    'rippletide': ["#A19E94", "13|-13|#9F9891, 4|5|#54544E", [657, 272, 671, 291]],
    'cragspear': ["#A19E94", "13|-13|#9F9891, 4|5|#575750", [658, 226, 748, 289]],
    'clearbrook': ["#A19E94", "13|-13|#9F9891, 4|5|#54544E", [745, 271, 759, 290]],
    'sunshade': ["#A19E94", "13|-13|#9F9891, 4|5|#54544E", [842, 238, 856, 257]],
    'shepherds-rock': ["#A19E94", "13|-13|#9F9891, 4|5|#54544E", [644, 272, 658, 291]],
}

bt_npc_exist = {
    'bt_axe': ["#D59590", "1|1|#D28F8A, 2|2|#D98882", [583, 275, 841, 337]],
    'bt_bow': ["#D59590", "1|1|#D28F8A, 2|2|#D98882", [582, 256, 949, 462]],
    'bt_tome': ["#D59590", "1|1|#D28F8A, 2|2|#D98882", [630, 220, 740, 330]],
    'bt_spear': ["#D59590", "1|1|#D28F8A, 2|2|#D98882", [764, 245, 1056, 344]],
    'bt_dagger': ["#D59590", "1|1|#D28F8A, 2|2|#D98882", [362, 206, 873, 544]],
    'bt_staff': ["#D59590", "1|1|#D28F8A, 2|2|#D98882", [362, 206, 873, 544]],
    'bt_fan': ["#D59590", "1|1|#D28F8A, 2|2|#D98882", [385, 285, 575, 350]],
    'bt_blade': ["#D59590", "1|1|#D28F8A, 2|2|#D98882", [500, 265, 860, 320]],
}

bt_ally_exist = {
    # 国际服比台服坐标高24单位
    'bt_axe': ["#492424", "1|1|#B8A994", [334, 215, 336, 241]],
    'bt_bow': ["#5D4B32", "1|1|#E4B98E", [334, 210, 336, 236]],
    'bt_tome': ["#002211", "1|1|#CF7853", [341, 215, 343, 241]],
    'bt_spear': ["#A9947D", "1|1|#EEBB99", [336, 205, 338, 231]],
    'bt_dagger': ["#BB7C60", "1|1|#A5AA88", [339, 207, 341, 233]],
    'bt_staff': ["#BCAD90", "1|1|#646854", [336, 205, 338, 231]],
    'bt_fan': ["#002211", "1|1|#FFEECC", [341, 218, 343, 244]],
    'bt_blade': ["#002211", "1|1|#FFEECC", [341, 218, 343, 244]],
}

enemy_exist = {
    'tikilen': {
        'statement': ["#F0EBE8", "-1|1|#F0EBE8, -2|2|#F0EBE8, -1|3|#F0EBE8, 0|5|#F0EBE8, 1|6|#F0EBE8", [105, 425, 150, 445]],
        'delta': [30, -45],
    },
    'elite-mercenary': {
        'statement': ["#F0EBE8", "0|1|#F0EBE8, 0|2|#F0EBE8, 0|3|#F0EBE8, 1|3|#F0EBE8, 2|3|#F0EBE8, 3|3|#F0EBE8", [270, 510, 325, 525]],
        'delta': [40, -50],
    },
    'veteran-mercenary': {
        'statement': ["#F0EBE8", "1|1|#F0EBE8, 1|2|#F0EBE8, 1|3|#F0EBE8, 2|4|#F0EBE8, 2|5|#F0EBE8, 3|6|#F0EBE8", [430, 385, 480, 405]],
        'delta': [45, -35],
    },
}

skill_boost_level_applied = {
    'tw': [
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1264, 148, 1266, 149]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1265, 142, 1267, 143]],
            '4': ["#FFFFFF", "1|0|#FFFFFF", [1242, 137, 1244, 138]],
        },
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1264, 291, 1266, 292]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1265, 285, 1267, 286]],
            '4': ["#FFFFFF", "1|0|#FFFFFF", [1242, 280, 1244, 281]],
        },
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1264, 434, 1266, 435]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1265, 428, 1267, 429]],
            '4': ["#FFFFFF", "1|0|#FFFFFF", [1242, 423, 1244, 424]],
        },
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1264, 577, 1266, 578]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1265, 571, 1267, 572]],
            '4': ["#FFFFFF", "1|0|#FFFFFF", [1242, 566, 1244, 567]],
        },
    ],
    'en': [
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1264, 148, 1266, 149]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1265, 142, 1267, 143]],
            '4': ["#FFFFFF", "0|1|#FFFFFF", [1242, 138, 1243, 140]],
        },
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1264, 291, 1266, 292]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1265, 285, 1267, 286]],
            '4': ["#FFFFFF", "0|1|#FFFFFF", [1242, 281, 1243, 283]],
        },
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1264, 434, 1266, 435]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1265, 428, 1267, 429]],
            '4': ["#FFFFFF", "0|1|#FFFFFF", [1242, 424, 1243, 426]],
        },
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1264, 577, 1266, 578]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1265, 571, 1267, 572]],
            '4': ["#FFFFFF", "0|1|#FFFFFF", [1242, 567, 1243, 569]],
        },
    ],
}

attack_boost_level_applied = {
    'tw': [
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1262, 148, 1264, 149]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1259, 142, 1261, 143]],
            '4': ["#FFFFFF", "1|0|#FFFFFF", [1257, 145, 1259, 146]],
        },
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1262, 291, 1264, 292]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1259, 285, 1261, 286]],
            '4': ["#FFFFFF", "1|0|#FFFFFF", [1257, 288, 1259, 289]],
        },
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1262, 434, 1264, 435]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1259, 428, 1261, 429]],
            '4': ["#FFFFFF", "1|0|#FFFFFF", [1257, 431, 1259, 432]],
        },
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1262, 577, 1264, 578]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1259, 571, 1261, 572]],
            '4': ["#FFFFFF", "1|0|#FFFFFF", [1257, 574, 1259, 575]],
        },
    ],
    'en': [
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1261, 148, 1263, 149]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1259, 142, 1261, 143]],
            '4': ["#FFFFFF", "0|1|#FFFFFF", [1261, 144, 1262, 146]],
        },
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1261, 291, 1263, 292]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1259, 285, 1261, 286]],
            '4': ["#FFFFFF", "0|1|#FFFFFF", [1261, 287, 1262, 289]],
        },
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1261, 434, 1263, 435]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1259, 428, 1261, 429]],
            '4': ["#FFFFFF", "0|1|#FFFFFF", [1261, 430, 1262, 432]],
        },
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1261, 577, 1263, 578]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1259, 571, 1261, 572]],
            '4': ["#FFFFFF", "0|1|#FFFFFF", [1261, 573, 1262, 575]],
        },
    ],
}


#   -------------------------------------------------------------------------------------------------
#   -------------------------------------------------------------------------------------------------
#   底层方法部分 - 底层操作，对小派API再封装以实现某些特殊效果。
#   -------------------------------------------------------------------------------------------------
#   -------------------------------------------------------------------------------------------------
def log(text):
    if turn_on_in_game_log:
        xp.log(text)
    if turn_on_console_log:
        xp.console(text)


def wait(t):
    _t = t + 0.2 * stability_mode
    # log("等待：" + str(_t) + "秒")
    sleep(_t)


def tap(x, y):
    _t = 0.05 + 0.02 * stability_mode
    # log("点击：" + str(x) + ", " + str(y))
    xp.tap(x, y, _t)
    sleep(_t + 0.01)


def tap_preset_coord(coord):
    tap(coord[0], coord[1])


def check_statement(statement):
    return xp.findColor(statement[0], statement[1], statement[2][0], statement[2][1], statement[2][2], statement[2][3])


def tap_preset_coord_with_checking(coord, statement, check_per_turn=5, interval=0.10, inverted=False):
    while True:
        tap_preset_coord(coord)
        for i in range(check_per_turn):
            wait(interval)
            if not inverted and check_statement(statement):
                return True
            if inverted and not check_statement(statement):
                return True


def tap_found_coord_with_checking(statement, interval=0.10, dx=0, dy=0):
    while True:
        found_coord = check_statement(statement)
        if found_coord:
            tap(found_coord.x + dx, found_coord.y + dy)
            return
        wait(interval)


def wait_with_checking(statement, max_turns=-1, interval=0.10, inverted=False):
    t = 0
    while True:
        wait(interval)
        t += 1
        if not inverted and check_statement(statement):
            return True
        if inverted and not check_statement(statement):
            return True
        if t == max_turns:
            return False


#   -------------------------------------------------------------------------------------------------
#   -------------------------------------------------------------------------------------------------
#   单元模块部分
#   -------------------------------------------------------------------------------------------------
#   -------------------------------------------------------------------------------------------------
def tap_skills_panel(n):
    # 检查技能面板是否开启需要注意，开局时漂浮移动的buff层级最高，会挡住技能面板，导致按键失效或判断错误
    return tap_preset_coord_with_checking(skills_panel_coord[n], battle_idling[region], inverted=True)


def tap_switch_character():
    return tap_preset_coord_with_checking(switch_character_coord[region], switch_character_done[region], interval=0.15)


def tap_skill(boost, x1, y1, x2=0, y2=0):
    # xp.tap(x1, y1, 0.25)
    # sleep(0.18)
    delay = 0.08 if boost == 1 else 0.15 + 0.02 * (boost - 1)
    xp.tap(x1, y1, delay)
    sleep(delay - 0.08)
    if x2 != 0 and y2 != 0:
        tap(x2, y2)


def tap_start_battle():
    return tap_preset_coord_with_checking(start_battle_btn_coord, battle_idling[region], check_per_turn=1, inverted=True)


def tap_flee_battle():
    return tap_preset_coord_with_checking(flee_battle_btn_coord, battle_idling[region], check_per_turn=1, inverted=True)


def tap_until_black_screen(coord):
    return tap_preset_coord_with_checking(coord, black_screen_exist, check_per_turn=1)


def tap_until_minimap_show(coord):
    return tap_preset_coord_with_checking(coord, minimap_exist, check_per_turn=1)


def tap_minimap():
    return tap_preset_coord_with_checking(minimap_coord, menu_exist[region], check_per_turn=1, inverted=True)


def tap_worldmap():
    return tap_preset_coord_with_checking(worldmap_btn_coord[region], menu_opened[region], check_per_turn=2, interval=0.3)


def tap_party():
    return tap_preset_coord_with_checking(party_btn_coord, menu_opened[region], check_per_turn=1, interval=0.2)


def tap_allies_list():
    return tap_preset_coord_with_checking(allies_list_btn_coord, allies_list_opened[region], check_per_turn=1, interval=0.2)


def tap_until_town_menu_opened(coord):
    return tap_preset_coord_with_checking(coord, town_menu_opened[region], check_per_turn=2, interval=0.3)


def tap_worldmap_proceed():
    return tap_preset_coord_with_checking(worldmap_proceed_btn_coord, ok_move_exist[region], check_per_turn=1, interval=0.2)


def tap_bt_npc(npc):
    return tap_found_coord_with_checking(bt_npc_exist[npc], interval=0.2)


def tap_inn_on_main_screen(town):
    return tap_found_coord_with_checking(inn_exist[town], interval=0.2)


def tap_inn_host(town):
    return tap_found_coord_with_checking(inn_host_exist[town], interval=0.2)


def tap_ally(ally):
    return tap_found_coord_with_checking(bt_ally_exist[ally], interval=0.2)


def tap_inquire():
    return tap_preset_coord_with_checking(inquire_btn_coord, inquire_menu_opened, check_per_turn=1, interval=0.2)


def tap_impress():
    return tap_preset_coord_with_checking(impress_btn_coord, confirm_impress_exist[region], check_per_turn=1, interval=0.2)


def tap_part_ways():
    return tap_preset_coord_with_checking(part_ways_btn_coord, ally_parting_ways[region], check_per_turn=1, interval=0.2)


def tap_confirm_part_ways():
    return tap_preset_coord_with_checking(general_ok_btn_coord, ally_parting_ways[region], check_per_turn=1, interval=0.2, inverted=True)


def tap_all_boost():
    return tap_preset_coord_with_checking(all_boost_btn_coord, character_all_boosted, check_per_turn=5, interval=0.1)


def tap_enemy(enemy):
    return tap_found_coord_with_checking(enemy_exist[enemy]['statement'], dx=enemy_exist[enemy]['delta'][0], dy=enemy_exist[enemy]['delta'][1])


def wait_skills_panel_shown():
    return wait_with_checking(skills_panel_standby[region], max_turns=10)


def wait_skills_panel_gone():
    return wait_with_checking(skills_panel_standby[region], max_turns=20, interval=0.05, inverted=True)


def wait_inquire_shown():
    return wait_with_checking(inquire_exist, max_turns=25, interval=0.2)


def wait_battle_idling(interval=0.5):
    return wait_with_checking(battle_idling[region], interval=interval)


def wait_black_screen_start():
    return wait_with_checking(black_screen_exist, interval=0.5)


def wait_black_screen_end():
    return wait_with_checking(black_screen_exist, interval=0.5, inverted=True)


def wait_main_screen_idling():
    return wait_with_checking(menu_exist[region], interval=0.2)


def wait_main_screen_idling_end():
    return wait_with_checking(menu_exist[region], interval=0.2, inverted=True)


def wait_minimap_disappear():
    return wait_with_checking(minimap_exist, interval=0.2, inverted=True)


def wait_allies_list_btn_shown():
    return wait_with_checking(allies_list_btn_exist[region], interval=0.2)


# def wait_bt_ally(ally):
#     return wait_with_checking(bt_ally_exist[ally], interval=0.2)


#   -------------------------------------------------------------------------------------------------
#   -------------------------------------------------------------------------------------------------
#   复合模块部分
#   -------------------------------------------------------------------------------------------------
#   -------------------------------------------------------------------------------------------------
def open_skills_panel(n):
    count = 0
    while True:
        if count > 0:
            log("【注意】：技能面板没有打开，重试")
        tap_skills_panel(n)
        count += 1
        if wait_skills_panel_shown():
            return


def await_black_screen_transition():
    wait_black_screen_start()
    wait_black_screen_end()


def open_minimap():
    wait_main_screen_idling()
    tap_minimap()


def open_worldmap():
    wait_main_screen_idling()
    tap_worldmap()


def open_party():
    wait_main_screen_idling()
    tap_party()


def open_allies_list():
    wait_allies_list_btn_shown()
    tap_allies_list()


def part_ways_ally(ally):
    # wait_bt_ally(ally)
    #   这里点击支援者如果失效，改成带检查重复点击的设计
    tap_ally(ally)
    tap_part_ways()
    tap_confirm_part_ways()
    tap_until_minimap_show(close_menu_btn_coord)


def move_using_minimap(coord):
    open_minimap()
    wait(0.3)
    tap_preset_coord(coord)


def move_using_worldmap(coord):
    open_worldmap()
    wait(0.5)
    tap_until_town_menu_opened(coord)
    tap_worldmap_proceed()
    tap_until_black_screen(general_ok_btn_coord)


#   -------------------------------------------------------------------------------------------------
# def use_skill(n, boost=1):
#     skill_coord = skills_coord[n][boost-1]
#     while True:
#         tap_skill(boost, skill_coord[0], skill_coord[1], skill_coord[2], skill_coord[3])
#         if wait_skills_panel_gone():
#             return
#   -------------------------------------------------------------------------------------------------
def use_skill(n, boost=1, t=0):
    if n == 5:
        tap(705, 93)
        wait(0.5)
        tap(923, 399)
        if wait_battle_idling():
            return
    skill_coord = skills_coord[region][n][boost - 1]
    count = 0
    while True:
        if count > 0:
            log("【注意】：重复点击技能")
        tap_skill(boost, skill_coord[0], skill_coord[1], skill_coord[2], skill_coord[3])
        if t != 0:
            wait(0.2)
            tap(skills_panel_coord[t-1][0], skills_panel_coord[t-1][1])
            wait(0.2)
        count += 1
        if wait_skills_panel_gone():
            return


def inquire_and_impress_bt_npc(npc):
    while True:
        tap_bt_npc(npc)
        if wait_inquire_shown():
            break
    tap_inquire()
    tap_impress()
    tap_until_black_screen(lower_ok_btn_coord)


def recover_in_inn(town):
    wait_main_screen_idling()
    #   这里点击旅店老板有概率失效，如果失效，改成带检查重复点击的设计
    tap_inn_host(town)
    wait_minimap_disappear()
    tap_until_black_screen(lower_ok_btn_coord)
    await_black_screen_transition()
    tap_until_minimap_show(center_ok_btn_coord)


def flee_battle():
    wait_battle_idling()
    tap_flee_battle()


def run_preset_character_action(n, action, retry=False):
    switch_character = action[0] > 9
    skill_to_use = action[0] % 10 if action[0] != -1 else -1
    boost_level = action[1]
    target_character = action[2]
    target_enemy = action[3]
    require_checking = False if boost_level == 1 else True

    if skill_to_use == -1:
        return
    open_skills_panel(n)

    if target_enemy != 0 and not retry:
        wait(0.2)
        tap_enemy(target_enemy)
        wait(0.2)

    if switch_character and not retry:
        tap_switch_character()
        # 国际服 - 切换完角色之后不做检查的话，会在瞬间完成以下动作：
        # 1.点击技能（但是面板未就绪，技能没有点上）
        # 2.检查技能面板解除（由于技能面板尚未显示，因此检查会通过）
        # 3.点击下一位角色的技能面板（由于上一位角色面板未消失，因此通过）
        # 4.点击下一位角色的技能（但是点成了上一位的）
        # 原因：因为台服检查的是底部的取消交替按钮，这个按钮的UI是最后出现的，因此检查到了必定切换完成且就绪，但是国际服检查的是顶部Front/Back，检查到的时候不一定就绪。
        if region == "en":
            wait_skills_panel_shown()
    use_skill(skill_to_use, boost_level, target_character)

    if not require_checking:
        return
    boost_level_applied = attack_boost_level_applied[region] if skill_to_use == 0 else skill_boost_level_applied[region]
    boost_level_check_result = wait_with_checking(boost_level_applied[n][str(boost_level)], max_turns=10)
    if not boost_level_check_result:
        log("【注意】：角色boost等级错误，重新使用技能")
        run_preset_character_action(n, action, retry=True)


def run_preset_turn_sequence(turn):
    all_boost = turn['all_boost']
    skill_list = turn['skill_list']

    wait_battle_idling()
    for n, character_action in enumerate(skill_list):
        character_action[1] = 1 if all_boost else character_action[1]
        run_preset_character_action(n, character_action)
    wait_battle_idling(0.1)
    tap_all_boost() if all_boost else None
    tap_start_battle()


def run_preset_battle_sequence(sequence_list):
    for i, sequence in enumerate(sequence_list):
        # log("开始第" + str(i+1) + "回合")
        run_preset_turn_sequence(sequence)
    tap_until_black_screen(screen_center_coord)


def move_towards_bt_npc(npc):
    if npc == 'bt_axe':
        move_using_minimap(valore_main_boulevard_coord)
        wait(8)
        await_black_screen_transition()
        move_using_minimap(bt_npc_coord_on_minimap[npc])
        wait(5)
    elif npc == 'bt_bow':
        # 方法1：通过小地图
        # move_using_minimap(emberglow_east_district_coord)
        # wait(15)
        # await_black_screen_transition()
        # move_using_minimap(bt_npc_coord_on_minimap[npc])
        # wait(12)
        # 方法2：通过大地图
        move_using_worldmap(emberglow_laboratory_coord)
        await_black_screen_transition()
        move_using_minimap(emberglow_laboratory_to_town_coord)
        await_black_screen_transition()
        move_using_minimap(bt_npc_coord_on_minimap[npc])
        wait(8)
    elif npc == 'bt_tome':
        move_using_minimap(theatropolis_library_coord)
        wait(15)
        await_black_screen_transition()
    elif npc == 'bt_spear':
        move_using_minimap(rippletide_residence_coord)
        wait(7)
        await_black_screen_transition()
    elif npc == 'bt_dagger':
        move_using_minimap(cragspear_slums_coord)
        wait(17)
        await_black_screen_transition()
        move_using_minimap(bt_npc_coord_on_minimap[npc])
        wait(9)
    elif npc == 'bt_staff':
        move_using_minimap(bt_npc_coord_on_minimap[npc])
        wait(5)
    elif npc == 'bt_fan':
        move_using_minimap(bt_npc_coord_on_minimap[npc])
        wait(6)
    elif npc == 'bt_blade':
        move_using_minimap(bt_npc_coord_on_minimap[npc])
        wait(6)


def run_script():
    total_count = 0
    while True:
        total_count += 1
        xp.log("第" + str(total_count) + "轮")
        start_time = time()

        # 战斗前
        move_towards_bt_npc(targeting_npc)

        for i in range(round_per_recover):
            inquire_and_impress_bt_npc(targeting_npc)
            await_black_screen_transition()

            # 战斗中
            xp.log("第" + str(i+1) + "场")
            # flee_battle()
            run_preset_battle_sequence(battle_sequence)
            tap_until_minimap_show(close_menu_btn_coord)

            # 战斗后
            open_party()
            open_allies_list()
            part_ways_ally(targeting_npc)

        move_using_worldmap(screen_center_coord)
        await_black_screen_transition()
        tap_inn_on_main_screen(get_town_name_by_npc[targeting_npc])
        await_black_screen_transition()
        recover_in_inn(get_town_name_by_npc[targeting_npc])
        move_using_minimap(inn_exit_coord[get_town_name_by_npc[targeting_npc]])
        await_black_screen_transition()

        xp.log("本轮用时：" + str(int(time() - start_time)) + "秒")
        log("------------------------")


memories_read_btn_coord = [1104, 507]
memories_ok_btn_coord = [700, 530]
memories_confirm_read = ["#FFFFFF", "1|0|#FFFFFF", [782, 590, 784, 591]]
memories_read_exist = ["#FFFFFF", "1|0|#FFFFFF", [1082, 498, 1084, 499]]


def tap_memories_read():
    return tap_preset_coord_with_checking(memories_read_btn_coord, memories_confirm_read, check_per_turn=1)


def tap_memories_ok_after_battle():
    return tap_preset_coord_with_checking(memories_ok_btn_coord, memories_read_exist, check_per_turn=1)


def run_tikilen_script():
    total_count = 0
    while True:
        total_count += 1
        xp.log("第" + str(total_count) + "轮")
        start_time = time()

        # 战斗前
        tap_memories_read()
        tap_until_black_screen([798, 600])
        await_black_screen_transition()
        xp.tap(640, 360, 2.5)
        wait(2.5)
        await_black_screen_transition()

        # 战斗 - 1
        run_preset_battle_sequence(battle_sequence)
        await_black_screen_transition()
        xp.tap(640, 360, 2.5)
        wait(2.5)
        await_black_screen_transition()

        # 战斗后
        tap_memories_ok_after_battle()

        xp.log("本轮用时：" + str(int(time() - start_time)) + "秒")
        log("------------------------")


run_tikilen_script()
